/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.rcs.adslmonitor;

import java.awt.Color;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.EventObject;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.SwingUtilities;

public class ManagerTrayIcon extends TrayIcon implements ADSLStatusListener {

  private int UPDATE_ICON_TIME = 1; // Cada segundo.
  private final String TITLE = "Monitor de routers ADSL";
  private final String INVISIBLE_SUBTITLE = "Haga click sobre el icono para mostrarlo.";
  private final String VISIBLE_SUBTITLE = "Haga click sobre el icono para ocultarlo.";
  private Window mainWindow;
  private ADSLStatus status;
  private static Image image = null;
  private Point trayScreenLocation;
  private long lastUpdateTime = 0;

  protected static Image createImage(String path, String description) {
    URL imageURL = ManagerTrayIcon.class.getResource(path);

    if (imageURL == null) {
      System.err.println("Resource not found: " + path);
      return null;
    } else {
      try {
        BufferedImage img = ImageIO.read(imageURL);
        return img;
      } catch (IOException ex) {
        Logger.getLogger(ManagerTrayIcon.class.getName()).log(Level.SEVERE, null, ex);
      }
      return (new ImageIcon(imageURL, description)).getImage();
    }
  }

  static {
    image = createImage("network-idle.png", "ADSL Router Monitor");
  }

  public ManagerTrayIcon(Window window, ADSLStatus adslStatus) {
    super(image);

    this.mainWindow = window;
    this.status = adslStatus;

    setToolTip("ADSL router monitor");
    setImageAutoSize(true);
//    addActionListener(new ActionListener() {
//      public void actionPerformed(ActionEvent e) {
//        if (null == trayScreenLocation)
//          trayScreenLocation = MouseInfo.getPointerInfo().getLocation();
//
//        showUI();
//      }
//    });

    addMouseListener(new MouseAdapter() {
      @Override
      public void mouseClicked(MouseEvent e) {
        trayScreenLocation = e.getLocationOnScreen();

        if (SwingUtilities.isRightMouseButton(e)) {
          showCurrentStatus();
        } else if (SwingUtilities.isLeftMouseButton(e)) {
          showUI();
        }
      }
    });

    status.addListener(this);
  }

  protected void showUI() {
    if (!mainWindow.isVisible()) {
      Dimension size = mainWindow.getSize();
      Point org = getTopLeft(size);

      mainWindow.setLocation(org.x, org.y);
      mainWindow.setVisible(true);
      mainWindow.toFront();
      mainWindow.requestFocusInWindow();
    } else {
      mainWindow.setVisible(false);
    }
  }

  private int getCorner() {
    Rectangle vr = getDesktopVisibleRectangle();
    int result = 0;

    if (Math.abs(trayScreenLocation.x - (int) vr.getMaxX()) < Math.abs(trayScreenLocation.x - (int) vr.getMinX())) {
      result = Rectangle2D.OUT_RIGHT;
    } else {
      result = Rectangle2D.OUT_LEFT;
    }

    if (Math.abs(trayScreenLocation.y - (int) vr.getMaxY()) < Math.abs(trayScreenLocation.y - (int) vr.getMinY())) {
      result = result | Rectangle2D.OUT_BOTTOM;
    } else {
      result = result | Rectangle2D.OUT_TOP;
    }

    return result;
  }

  private Point getTopLeft(Dimension dim) {
    Rectangle vr = getDesktopVisibleRectangle();
    int corner = getCorner();
    Point result;

    switch (corner) {
      case Rectangle2D.OUT_TOP | Rectangle2D.OUT_LEFT:
        result = new Point(vr.x, vr.y);
        break;
      case Rectangle2D.OUT_TOP | Rectangle2D.OUT_RIGHT:
        result = new Point((int) vr.getMaxX() - dim.width, vr.y);
        break;

      case Rectangle2D.OUT_BOTTOM | Rectangle2D.OUT_LEFT:
        result = new Point(vr.x, (int) vr.getMaxY() - dim.height);
        break;

      case Rectangle2D.OUT_BOTTOM | Rectangle2D.OUT_RIGHT:
        result = new Point((int) vr.getMaxX() - dim.width, (int) vr.getMaxY() - dim.height);
        break;

      default:
        result = new Point();
    }

    return result;
  }

  private Rectangle getDesktopVisibleRectangle() {
    GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
    GraphicsConfiguration cg = device.getDefaultConfiguration();
    Rectangle bounds = cg.getBounds();
    Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(cg);

    bounds.x += insets.left;
    bounds.y += insets.top;
    bounds.width -= insets.right;
    bounds.height -= insets.bottom;

    return bounds;
  }

  public void showInitialMessage() {
    displayMessage(TITLE, getSubtitle(), TrayIcon.MessageType.INFO);
  }

  public String getSubtitle() {
    if (mainWindow.isVisible()) {
      return VISIBLE_SUBTITLE;
    } else {
      return INVISIBLE_SUBTITLE;
    }
  }

  public void showCurrentStatus() {
    if (status.hasError()) {
      displayMessage(TITLE, getSubtitle() + "\n" + status.getLastError(), TrayIcon.MessageType.ERROR);
    } else {
      if (!Desktop.isDesktopSupported() || !Desktop.getDesktop().isSupported(Desktop.Action.BROWSE))
        displayMessage(TITLE,
                String.format("%s\nBajada : %s/%s %s/%s\nSubida : %s/%s %s/%s",
                getSubtitle(),
                status.get(ADSLStatus.KEYS.DOWN_STREAM), status.get(ADSLStatus.KEYS.ATTAINABLE_DOWN_RATE),
                status.get(ADSLStatus.KEYS.ATTENUATION_DOWN_STREAM), status.get(ADSLStatus.KEYS.SNR_MARGIN_DOWN_STREAM),
                status.get(ADSLStatus.KEYS.UP_STREAM), status.get(ADSLStatus.KEYS.ATTAINABLE_UP_RATE),
                status.get(ADSLStatus.KEYS.ATTENUATION_UP_STREAM), status.get(ADSLStatus.KEYS.SNR_MARGIN_UP_STREAM)), TrayIcon.MessageType.INFO);
      else {
        try {
          URL url = status.getRouterURLForBrowser();          
          URI uri = url.toURI() ;
          
          Desktop.getDesktop().browse(uri);
        } catch (IOException ex) {
          displayMessage(TITLE, getSubtitle() + "\n" + ex.getLocalizedMessage(), TrayIcon.MessageType.ERROR);
        } catch (URISyntaxException ex) {
          displayMessage(TITLE, getSubtitle() + "\n" + ex.getLocalizedMessage(), TrayIcon.MessageType.ERROR);
        }
      }
    }
  }
  static Window win;

  public static BufferedImage scaleImage(BufferedImage image, int maxSideLength) {
    assert (maxSideLength > 0);
    double originalWidth = image.getWidth();
    double originalHeight = image.getHeight();
    double scaleFactor = 0.0;
    if (originalWidth > originalHeight) {
      scaleFactor = ((double) maxSideLength / originalWidth);
    } else {
      scaleFactor = ((double) maxSideLength / originalHeight);
    }
    // create smaller image
    BufferedImage img = new BufferedImage((int) (originalWidth * scaleFactor), (int) (originalHeight * scaleFactor), image.getType());
    // fast scale (Java 1.4 & 1.5)
    Graphics g = img.getGraphics();
    g.drawImage(image, 0, 0, img.getWidth(), img.getHeight(), null);

    return img;
  }

  protected void changeIconStatus(ADSLStatus status) {

    // Time to change the image.
    long newTime = System.currentTimeMillis();

    setToolTip(String.format("ADSL router monitor\nBajada : %s kbps\nSubida : %s kbps", status.get(ADSLStatus.KEYS.DOWN_STREAM), status.get(ADSLStatus.KEYS.UP_STREAM)));

    if (newTime - lastUpdateTime > UPDATE_ICON_TIME * 1000) {

      Dimension dim = getSize();

      final BufferedImage img = scaleImage((BufferedImage) image, dim.width > dim.height ? dim.width : dim.height);

      //Image img = image.getScaledInstance(-1, -1, Image.SCALE_REPLICATE) ;
      Graphics2D g = img.createGraphics();

      g.setColor(Color.black);
      g.fillRect(0, 0, img.getWidth() - 1, img.getHeight() - 1);

      g.setFont(new Font("Courier", Font.BOLD, 7));
      g.setColor(Color.yellow);
      
      String down = status.get(ADSLStatus.KEYS.DOWN_STREAM) ;
      String up = status.get(ADSLStatus.KEYS.UP_STREAM) ;
      
      g.drawString(null == down ? "-" : down, 0, img.getHeight() / 4);
      g.drawString(null == up ? "-" : up, 0, (int) (img.getHeight() * 3.0 / 4));

      setImage(img);
      g.dispose();

      lastUpdateTime = newTime;
    }
  }

  public void statusChanged(EventObject evt) {
    ADSLStatus adslStatus = (ADSLStatus) evt.getSource();

    changeIconStatus(adslStatus);
  }
}
